/*
 * 描述： <描述>
 * 修改人： rain
 * 修改时间： 2016年9月22日
 * 项目： rainhy-core
 */
package com.rainhy.webcore.util;

import java.lang.reflect.Field;
import java.lang.reflect.Proxy;

import org.springframework.aop.SpringProxy;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;
import org.springframework.util.ClassUtils;

/**
 * 
 * 代理对象工具类
 * 
 * @author rain
 * @version [版本号, 2016年9月22日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class ProxyUtils {
    
    /**
     * 
     * 是否是SpringAop代理对象<br>
     * 判断这传入的对象是一个 JDK Dynamic 代理对象或者是一个 CGLIB 代理对象.<br>
     * 同时此对象是{@link SpringProxy}的实现
     *
     * @param springAopProxy 对象
     * 
     * @return boolean [返回类型说明]
     * @throws [异常类型] [异常说明]
     * @see org.springframework.aop.support.AopUtils#isAopProxy(Object)
     * @version [版本号, 2016年9月22日]
     * @author rain
     */
    public static boolean isAopProxy(Object springAopProxy) {
        return AopUtils.isAopProxy(springAopProxy);
    }
    
    /**
     * 
     * 是否是代理对象<br>
     * 判断这传入的对象是一个 JDK Dynamic 代理对象或者是一个 CGLIB 代理对象.<br>
     *
     * @param proxy 对象
     * 
     * @return boolean [返回类型说明]
     * @throws [异常类型] [异常说明]
     * @see java.lang.reflect.Proxy#isProxyClass(Class)
     * @see org.springframework.util.ClassUtils#isCglibProxy(Object)
     * @version [版本号, 2016年9月22日]
     * @author rain
     */
    public static boolean isProxy(Object proxy) {
        return Proxy.isProxyClass(proxy.getClass()) || ClassUtils.isCglibProxy(proxy);
    }
    
    /**
     * 
     * 获取代理对象实例<br>
     * 传入的对象是一个 JDK Dynamic 代理对象或者是一个 CGLIB 代理对象.<br>
     * 如果传入的不是 jdk 和 cglib 代理对象,则直接返回此对象
     *
     * @param proxy 代理对象
     * 
     * @return Object [返回类型说明]
     * @throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年9月22日]
     * @author rain
     */
    public static Object getTarget(Object proxy) throws Exception {
        if (Proxy.isProxyClass(proxy.getClass())) {
            return getJdkDynamicProxyTargetObject(proxy);
        } else if (ClassUtils.isCglibProxy(proxy)) {
            return getCglibProxyTargetObject(proxy);
        } else {
            return proxy;
        }
    }
    
    /**
     * 
     * 获取cglib代理对象实例
     *
     * @param proxy cglib代理对象
     * 
     * @return Object cglib代理对象实例
     * @throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年9月22日]
     * @author rain
     */
    private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
        Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
        h.setAccessible(true);
        Object dynamicAdvisedInterceptor = h.get(proxy);
        
        Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
        advised.setAccessible(true);
        Object target = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
        return target;
    }
    
    /**
     * 
     * 获取jdk动态代理对象的实例
     * 
     * @param proxy jdk动态代理对象
     * 
     * @return Object jdk动态代理对象的实例
     * @throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年9月22日]
     * @author rain
     */
    private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
        Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
        h.setAccessible(true);
        AopProxy aopProxy = (AopProxy) h.get(proxy);
        
        Field advised = aopProxy.getClass().getDeclaredField("advised");
        advised.setAccessible(true);
        
        Object target = ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget();
        return target;
    }
}
